home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / mp threaded sort / dialogutils.cp < prev    next >
Encoding:
Text File  |  2000-09-28  |  10.6 KB  |  394 lines

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by:     
  9.  
  10.     Copyright:    Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
  11.  
  12.                 You may incorporate this Apple sample source code into your program(s) without
  13.                 restriction. This Apple sample source code has been provided "AS IS" and the
  14.                 responsibility for its operation is yours. You are not permitted to redistribute
  15.                 this Apple sample source code as "Apple sample source code" after having made
  16.                 changes. If you're going to re-distribute the source, we require that you make
  17.                 it clear in the source that the code was descended from Apple sample source
  18.                 code, but that you've made changes.
  19.  
  20.     Change History (most recent first):
  21.                 7/27/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  22.                 11/16/94    DRF                Added explicit #include <SegLoad.h> for latest universal
  23.                                             headers. Also added cast to keep MPW CFront happier.
  24.                 11/16/94    DRF                Add StdFilterProc for THINK C.
  25.                  9/27/94    DRF                 AppLib.h is now Sprocket.h
  26.                   9/9/94    DRF                Reordered headers and removed redundant #includes.
  27.  
  28. */
  29.  
  30. #include "Sprocket.h"
  31. extern pascal void ExitToShell(void );
  32.  
  33. #include <Fonts.h>
  34. #include <Resources.h>
  35. #include <TextUtils.h>
  36. #include <Threads.h>        //    For YieldToAnyThread()
  37. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  38. #include <SegLoad.h>        //    For ExitToShell()
  39. #include <Controls.h>
  40.  
  41. //    Some types which should probably be defined in <Dialogs.h>
  42. //    NOTE: These must be aligned on 2-byte boundaries
  43. #if defined(powerc) || defined (__powerc)
  44. #pragma options align=mac68k
  45. #endif
  46.  
  47. struct DialogItem
  48.     {
  49.     long    usedByDialogManager;
  50.     Rect    boundsRect;
  51.     char    type;
  52.     char    length;
  53.     };
  54.  
  55. struct DialogItemList            //    a.k.a. a 'DITL'
  56.     {
  57.     short        count;
  58.     DialogItem    firstItem[1];
  59.     };
  60.  
  61. //    Restore default alignment
  62. #if defined(powerc) || defined(__powerc)
  63. #pragma options align=reset
  64. #endif
  65.  
  66. typedef    DialogItem        *DialogItemPtr;
  67. typedef    DialogItemList    **DialogItemListHandle;
  68. typedef    DialogTemplate    **DialogTemplateHandle;
  69.  
  70. #ifndef    powerc
  71. #ifdef    __SC__
  72.  
  73. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  74.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  75.  
  76. pascal Boolean
  77. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  78.     {
  79.     ModalFilterUPP    filterUPP;
  80.  
  81.     //    Dialogs.h
  82.     
  83.     (void) GetStdFilterProc(&filterUPP);
  84.  
  85.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  86.     }
  87.  
  88. #endif
  89. #endif
  90.  
  91. //    private function Prototypes
  92.  
  93. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  94. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  95. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  96. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  97.  
  98.  
  99.  
  100. ///////////////////////////////////////////////////////////
  101. //
  102. //    StandardAlert
  103. //
  104. //    An alternative to Alert() which uses the extended
  105. //    Dialog Manager capabilities.
  106. //
  107. //    I’m not sure we really need this call, but it seems
  108. //    to do the trick just fine.
  109.  
  110. short
  111. StandardAlert(    short dlogID,
  112.                 short defaultItem,                /* = ok */
  113.                 short cancelItem,                /* = 0 */
  114.                 ModalFilterUPP customFilterProc    /* = nil */)
  115.     {
  116.     DialogPtr        theDialog;
  117.     short            itemHit = 0;
  118.     ModalFilterUPP    filterToUse;
  119.     
  120.     HiliteWindowsForModalDialog(false);
  121.  
  122.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  123.     if (defaultItem)
  124.         SetDialogDefaultItem(theDialog,defaultItem);
  125.     if (cancelItem)
  126.         SetDialogCancelItem(theDialog,cancelItem);
  127.  
  128.     if (customFilterProc)
  129.         filterToUse = customFilterProc;
  130.     else
  131.         filterToUse = StandardDialogFilter;
  132.  
  133.     do
  134.         ModalDialog(filterToUse,&itemHit);
  135.     while (itemHit == 0);
  136.     
  137.     DisposeDialog(theDialog);
  138.  
  139.     HiliteWindowsForModalDialog(true);
  140.  
  141.     return itemHit;
  142.     }
  143.  
  144.  
  145. ///////////////////////////////////////////////////////////
  146. //
  147. //    ErrorAlert
  148. //
  149. //    A nice error reporting routine which presents an
  150. //    auto-sized alert box containing the supplied text.
  151. //
  152. //    NOTE:    This routine ASSUMES the following 'DITL'
  153. //            structure:
  154. //
  155. //            item #1 : an “OK” button
  156. //            item #2 : a static text item, somewhere above #1
  157. //
  158. //    NOTE:    We probably need to worry more about low
  159. //            memory conditions-- this can probably
  160. //            be handled by a custom GrowZoneProc and
  161. //            reserve memory area large enough to hold
  162. //            all the space we’d need.
  163. //
  164.  
  165. void
  166. ErrorAlert(short stringList,short whichString)
  167.     {
  168.     Str255                    errorString;
  169.     GrafPtr                    oldPort,windowMgrPort;
  170.     short                    oldFont;
  171.     DialogTemplateHandle    errorDialogTemplate;
  172.     DialogItemListHandle    errorDialogItems;
  173.     TEHandle                aTEHandle;
  174.     Rect                    textRect;
  175.     short                    textHeight;
  176.     short                    additionalSpaceNeeded;
  177.     DialogItemPtr            okButtonItem,errorTextItem;
  178.     const StringPtr            nullStr = (StringPtr) "\p";
  179.  
  180.     GetIndString(errorString,stringList,whichString);
  181.     
  182.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  183.     HLock((Handle) errorDialogTemplate);
  184.     
  185.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  186.     HLock((Handle) errorDialogItems);
  187.     
  188.     //    Find the dialog items
  189.     
  190.     okButtonItem = (**errorDialogItems).firstItem;
  191.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  192.     
  193.     GetPort(&oldPort);
  194.     GetWMgrPort(&windowMgrPort);
  195.     SetPort(windowMgrPort);
  196.     oldFont = qd.thePort->txFont;
  197.     TextFont(systemFont);
  198.  
  199.     aTEHandle = TENew(&textRect,&textRect);
  200.     TESetText(&errorString[1],errorString[0],aTEHandle);
  201.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  202.     TEDispose(aTEHandle);
  203.  
  204.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  205.                             - errorTextItem->boundsRect.top);
  206.  
  207.     if (additionalSpaceNeeded > 0)
  208.         {
  209.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  210.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  211.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  212.         }
  213.         
  214.     TextFont(oldFont);
  215.     SetPort(oldPort);
  216.     
  217.     InitCursor();
  218.     ParamText(errorString,nullStr,nullStr,nullStr);
  219.  
  220.     (void) StandardAlert(kErrorAlertID);
  221.  
  222.     ReleaseResource((Handle) errorDialogTemplate);
  223.     ReleaseResource((Handle) errorDialogItems);
  224.     }
  225.  
  226.  
  227. ///////////////////////////////////////////////////////////
  228. //
  229. //    FatalErrorAlert
  230. //
  231. //    A companion to ErrorAlert which also kills the process.
  232. //
  233.  
  234. void
  235. FatalErrorAlert(short stringList,short whichString)
  236.     {
  237.     ErrorAlert(stringList,whichString);
  238.     ExitToShell();
  239.     }
  240.  
  241.  
  242. ///////////////////////////////////////////////////////////
  243. //
  244. //    StandardDialogFilter and StandardDialogFilterYD
  245. //
  246. //    These function takes care of routing events not meant
  247. //    for the dialog window to other parts of the application.
  248. //
  249. //    Use them as an alternative to passing a NIL ModalFilterProc
  250. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  251. //    filter, these routines properly processes update events
  252. //    to keep background processes running.
  253. //
  254. //    The Thread Manager, if present, is also called to yield
  255. //    control to other cooperative threads within the process.
  256. //
  257. //    Because of pascal calling conventions we need two separate
  258. //    routines, but this is minimized by sharing implementation
  259. //    in FilterProcCommon.
  260. //
  261.  
  262. ModalFilterUPP    StandardDialogFilter
  263. = NewModalFilterProc(StandardDialogFilterProc);
  264.  
  265. ModalFilterYDUPP    StandardDialogFilterYD
  266. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  267.  
  268. ModalFilterUPP    StandardCloseDialogFilter
  269. = NewModalFilterProc(StandardCloseDialogFilterProc);
  270.  
  271.  
  272. pascal Boolean
  273. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  274.     {
  275.     //    Call through common code to check for events we’d like to handle.
  276.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  277.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  278.  
  279.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  280.         return true;
  281.     else
  282.         return (StdFilterProc(theDialog, anEvent, itemHit));
  283.     }
  284.  
  285.  
  286. pascal Boolean
  287. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  288.     {
  289.     //    We don’t call through to StdFilterProc since the
  290.     //    Standard File Package already does everything we need.
  291.  
  292.     return FilterProcCommon(theDialog, anEvent, itemHit);
  293.     }
  294.  
  295. void
  296. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  297.     {
  298.     Handle    itemHandle;
  299.     Rect    itemBox;
  300.     unsigned long    finalTicks;
  301.     short    itemType;
  302.     
  303.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  304.  
  305.     HiliteControl((ControlHandle) itemHandle, kControlButtonPart);
  306.     Delay(8,&finalTicks);
  307.     HiliteControl((ControlHandle) itemHandle,0);
  308.     }
  309.  
  310.  
  311. pascal Boolean
  312. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  313.     {
  314.     if ((anEvent->what == keyDown))
  315.         {
  316.         char    c = (char) anEvent->message & charCodeMask;
  317.         
  318.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  319.             {
  320.             *itemHit = kDontSaveDocument;
  321.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  322.             return true;
  323.             }
  324.         }
  325.  
  326.     //    Return through the common code above so that default item processing can happen
  327.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  328.     }
  329.  
  330.  
  331. Boolean
  332. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  333.     {
  334.     switch (anEvent->what)
  335.         {
  336.         case updateEvt:
  337.         case activateEvt:
  338.             //     Update or activate for the dialog window?
  339.             if (theDialog == (DialogPtr) anEvent->message)
  340.                 break;
  341.  
  342.             //    no, fall through to HandleEvent            
  343.             
  344.         case diskEvt:
  345.             HandleEvent(anEvent);
  346.             return(false);
  347.  
  348.         default:
  349.             break;        
  350.         }
  351.  
  352.     if (gHasThreadManager)        //    If we have threads, let them run!
  353.         YieldToAnyThread();
  354.  
  355.     return false;                //    We didn’t handle the event
  356.     }
  357.  
  358.  
  359. //////////////////////////////////////////////////////////////////
  360. //
  361. //    StandardCloseDocument
  362. //
  363. //    Provides the standard human interface for closing a document
  364. //
  365. //    NOTE: When we make TDocument class, this will become a method
  366. //          and probably won’t need any parameters.
  367. //
  368. //    NOTE:    StandardCloseResult matches the dialog items for 
  369.  
  370. StandardCloseResult
  371. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  372.                       Boolean hasNewEditions, Boolean quitting)
  373.     {
  374.     short        whichAlert;
  375.     short        whichString;
  376.     StringPtr    nullStr = (StringPtr) "\p";
  377.     Str255        reasonForClosingStr;
  378.  
  379.     if (hasNewEditions)
  380.         whichAlert = kStandardCloseWithNewPubsAlertID;
  381.     else
  382.         whichAlert = kStandardCloseAlertID;
  383.     
  384.     if (quitting)
  385.         whichString = kQuittingStr;
  386.     else
  387.         whichString = kClosingStr;
  388.  
  389.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  390.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  391.     
  392.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  393.     }
  394.